package eclipse.client;

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import com.sun.opengl.util.texture.*;
import eclipse.*;
import eclipse.client.threadpool.*;
import eclipse.client.forms.*;
import eclipse.lib.*;
import eclipse.lib.graphics.*;
import eclipse.lib.sound.*;
import eclipse.lib.sockets.*;
import eclipse.util.*;
import eclipse.util.io.*;
/**
 * The Loader class loads all the data that the Client will potentially used.
 * This is called at the start of either the Application or the Applet.
 */
/*
 * Copyright (c) 2009, TOD Productions All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *	- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *	- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *	-Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
public final class Loader
{
	//object used to draw the loading bar to
	private final JPanel loaderSurface;
	//loading bar used to display loading status
	private final JProgressBar loaderBar;
	//this thread really just updates the title really
	private final LoaderThread loaderThread;
	
	/**
	 * returns the Container object for the JPanel associated with the status bar.
	 * @return
	 */
	public final Container getSurface()
	{
		//return the object used to render the loader to
		return loaderSurface;
	}	
	
	/**
	 * Initializes the loader Object. 
	 * This object then loads all the data used in the Database class.	 
	 */
	public Loader()
	{
		//build the panel to draw to
		loaderSurface 	= new JPanel();
		//add the progress bar
		loaderBar		= new JProgressBar(0, 100);
		//start the thread, this just updates the title
		loaderThread 	= new LoaderThread();
		//allow the loader bar to display text
		loaderBar.setStringPainted(true);
		//add the loader bar to the surface
		loaderSurface.add(loaderBar);				
		
		//this was moved to static main() of the Application
		
		//System.out.println("Loading INI..."); 		Loader.INIInit();
		//System.out.println("Loading TCP..."); 		Loader.TCPInit(0);
		//System.out.println("Loading Threads..."); 	Loader.ThreadInit();
		//System.out.println("Loading GUI..."); 		Loader.GUIInit();	
	}	
	/**
	 * Initializes all the threads.	 
	 */
	public final void ThreadInit()
	{	
		//get the value of the loader bar, this should be 0
		final int val = loaderBar.getValue();
		//set the bar's status
		loaderBar.setString("Loading Threads...");
		//open the property file: "config"
		final PropertyFile pFile = new PropertyFile(new ERL("jar://config").openStream());
		//read the music file
		final String menuMusic = pFile.readProperty("MAINMENU", "MUSIC");
		//load the Audio player
		Database.audioChannel = new AudioDevice();
		
		//update the loader bar
		for(int i = 0; i < 10; i++)
		{
			//this is probably not the best way, could just do val + 10...
			loaderBar.setValue(val + i);
		}
		
		//check to confirm that music should be played
		if(menuMusic.trim().length() != 0)
		{
			//load the music
			Database.audioChannel.loadAudio(menuMusic);
			//loop that music
			Database.audioChannel.loopAudio();
		}
		
		//build the thread pool
		Database.threadCache = new ThreadCache();
		
		//update the loader
		for(int i = 10; i < 20; i++)
		{
			//again, could just use the val + 10...
			loaderBar.setValue(val + i);
		}
	}
	/**
	 * Loads the tcp connection. 
	 * @param serverIndex represents the server the client will attempt to connect to.
	 */
	public final void TCPInit(int serverIndex)	
	{	
		//get the current value of the loader bar
		final int val = loaderBar.getValue();
		//update the caption
		loaderBar.setString("Loading TCP...");
		//remove the socket's pointer
		Database.Socket = null;
		//set the socket's pointer
		Database.Socket = new ClientSocket
		(
			//get the IP from the server
			Database.SERVERIP.get(serverIndex),
			//convert the String port to an integer
			Integer.parseInt(Database.SERVERPORT.get(serverIndex).toString())
		);
		//update the value +20
		for(int i = 0; i < 20; i++)
			loaderBar.setValue(val + i);		
	}
	/**
	 * Loads the game's Database from the config file.
	 *
	 */
	public final void INIInit()
	{
		int val = loaderBar.getValue();
		loaderBar.setString("Loading INI...");
		final PropertyFile pData = new PropertyFile(new ERL("jar://config").openStream());
		
		Database.TILEDATABASE = pData.readProperty("ENGINE", "DATABASE", "TILEDIR");
		Database.SPRITEDATABASE = pData.readProperty("ENGINE", "DATABASE", "SPRITEDIR");
		Database.MAXSERVERS = Integer.parseInt(pData.readProperty("SERVERCOUNT"));
		Database.SERVERIP 	= new ArrayList	<String>	(Database.MAXSERVERS);
		Database.SERVERPORT = new ArrayList	<Object>	(Database.MAXSERVERS);
		Database.SERVERNAME = new ArrayList <String>	(Database.MAXSERVERS);
		loaderBar.setValue(++val);
		for(int i = 0; i < Database.MAXSERVERS; i++)
		{
			Database.SERVERIP.add(		
					pData.readProperty("SERVER" + i, "IP"));
			Database.SERVERPORT.add(
					Integer.parseInt(
						pData.readProperty("SERVER" + i, "PORT")));
			Database.SERVERNAME.add(
					pData.readProperty("SERVER" + i, "NAME"));
		}
		loaderBar.setValue(++val);
		Database.IMGMAINMENU	= pData.readProperty("MAINMENU", "GUI");
		Database.IMGLOGIN		= pData.readProperty("LOGIN", "GUI");
		Database.IMGNEWCHARACTER	= pData.readProperty("NEWCHARACTER", "GUI");
		Database.IMGNEWACCOUNT	= pData.readProperty("NEWACCOUNT", "GUI");
		Database.IMGMIRAGEMENU	= pData.readProperty("MIRAGE", "MINIMENU", "GUI");
		loaderBar.setValue(++val);
		loaderBar.setValue(++val);
		Database.MAINMENUEXITX = Integer.parseInt(pData.readProperty("MAINMENU", "EXIT", "X"));
		Database.MAINMENUEXITW = Integer.parseInt(pData.readProperty("MAINMENU", "EXIT", "W"));
		Database.MAINMENUEXITY = Integer.parseInt(pData.readProperty("MAINMENU", "EXIT", "Y"));
		Database.MAINMENUEXITH = Integer.parseInt(pData.readProperty("MAINMENU", "EXIT", "H"));
		loaderBar.setValue(++val);
		Database.MAINMENULOGINX = Integer.parseInt(pData.readProperty("MAINMENU", "LOGIN", "X"));
		Database.MAINMENULOGINY = Integer.parseInt(pData.readProperty("MAINMENU", "LOGIN", "Y"));
		Database.MAINMENULOGINW = Integer.parseInt(pData.readProperty("MAINMENU", "LOGIN", "W"));
		Database.MAINMENULOGINH = Integer.parseInt(pData.readProperty("MAINMENU", "LOGIN", "H"));
		loaderBar.setValue(++val);
		Database.MAINMENUNEWACCOUNTX = Integer.parseInt(pData.readProperty("MAINMENU", "NEWACCOUNT", "X"));
		Database.MAINMENUNEWACCOUNTY = Integer.parseInt(pData.readProperty("MAINMENU", "NEWACCOUNT", "Y"));
		Database.MAINMENUNEWACCOUNTH = Integer.parseInt(pData.readProperty("MAINMENU", "NEWACCOUNT", "H"));
		Database.MAINMENUNEWACCOUNTW = Integer.parseInt(pData.readProperty("MAINMENU", "NEWACCOUNT", "W"));
		loaderBar.setValue(++val);		
		loaderBar.setValue(++val);				
		loaderBar.setValue(++val);
		loaderBar.setValue(++val);
		Database.LOGINEXITX = Integer.parseInt(pData.readProperty("LOGIN", "EXIT", "X"));
		Database.LOGINEXITY = Integer.parseInt(pData.readProperty("LOGIN", "EXIT", "Y"));
		Database.LOGINEXITW = Integer.parseInt(pData.readProperty("LOGIN", "EXIT", "W"));
		Database.LOGINEXITH = Integer.parseInt(pData.readProperty("LOGIN", "EXIT", "H"));
		loaderBar.setValue(++val);
		Database.LOGINLOGINX = Integer.parseInt(pData.readProperty("LOGIN", "LOGIN", "X"));
		Database.LOGINLOGINY = Integer.parseInt(pData.readProperty("LOGIN", "LOGIN", "Y"));
		Database.LOGINLOGINW = Integer.parseInt(pData.readProperty("LOGIN", "LOGIN", "W"));
		Database.LOGINLOGINH = Integer.parseInt(pData.readProperty("LOGIN", "LOGIN", "H"));
		loaderBar.setValue(++val);		
		loaderBar.setValue(++val);		
		loaderBar.setValue(++val);		
		loaderBar.setValue(++val);		
		Database.NEWACCOUNTCONFH	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "CONF", "H"));
		Database.NEWACCOUNTCONFW	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "CONF", "W"));
		Database.NEWACCOUNTCONFX	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "CONF", "X"));
		Database.NEWACCOUNTCONFY	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "CONF", "Y"));
		Database.NEWACCOUNTEXITH	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "EXIT", "H"));
		Database.NEWACCOUNTEXITW	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "EXIT", "W"));
		Database.NEWACCOUNTEXITX	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "EXIT", "X"));
		Database.NEWACCOUNTEXITY	= Integer.parseInt(pData.readProperty("NEWACCOUNT", "INPUT", "EXIT", "Y"));
		Database.MAX_SPRITESETS		= Integer.parseInt(pData.readProperty("SPRITESET", "COUNT"));
		Database.MAX_TILESETS		= Integer.parseInt(pData.readProperty("TILESET", "COUNT"));
		Database.tTileSheet 		= new Texture[Database.MAX_TILESETS];
		Database.tSpriteSheet		= new Texture[Database.MAX_SPRITESETS];
		Database.ID_LAYER			= new int[10];
		Database.MAX_MAPS 			= Integer.parseInt(pData.readProperty("MAPS", "COUNT"));
		loaderBar.setValue(++val);
		if(pData.readProperty("ENGINE", "RES").contains("H"))
			Database.HIGH_RES = true;
		else
			Database.HIGH_RES = false;
		if(Integer.parseInt(pData.readProperty("ENGINE", "DIM")) == 3)
			Database.RENDER_AS_3D = true;
		else
			Database.RENDER_AS_3D = false;
		final String lag = pData.readProperty("ENGINE", "LATENCY");
		if(lag.equals("EXTRALOW"))
			Database.lag = LATENCY.EXTRALOW;
		else if(lag.equals("LOW"))
			Database.lag = LATENCY.LOW;
		else if(lag.equals("MEDIUM"))
			Database.lag = LATENCY.MEDIUM;
		else if(lag.equals("HIGH"))
			Database.lag = LATENCY.HIGH;
		else
			Database.lag = LATENCY.EXTRAHIGH;
		Database.FPS				= Integer.parseInt(pData.readProperty("ENGINE", "FPS")) + 1;		
		pData.closeProperty();
		loaderBar.setValue(++val);loaderBar.setValue(++val);loaderBar.setValue(++val);
	}
	/**
	 * Initializes the graphics and OpenGL object.
	 *
	 */
	public final void GUIInit()
	{		
		int val = loaderBar.getValue();
		loaderBar.setString("Loading Graphics...");
		final Renderer glObject = new Renderer();
		val += 10;
		loaderBar.setValue(val);
		try
		{
			loaderBar.setString("Loading OpenGL...");
			ServerList.makeGUI();		
			if(!Database.APPLET)
			{
				Database.Eclipse		 = new StandardForm(Constants.ENGINE, 640, 480, 200, 200);				
				Database.drawSurface = Database.Eclipse;				
			}
			Database.glInterface = new GLInterface(Database.drawSurface, glObject);										
			val += 10;
			loaderBar.setValue(val);
			loaderBar.setString("Loading Forms...");
			Database.MainMenu = new MainMenu("Main Menu", 300, 100, new ERL(Database.IMGMAINMENU));
				new MouseHandler(Database.MainMenu, Constants.MENUSTATE_MAINMENU);
			loaderBar.setValue(85);
			Database.Login = new Login("Login", 300, 100, new ERL(Database.IMGLOGIN));
				new MouseHandler(Database.Login, Constants.MENUSTATE_LOGINMENU);
			loaderBar.setValue(90);	
			Database.NewCharacter = new NewCharacter("New Character", 300, 100, new ERL(Database.IMGNEWCHARACTER));
				
			loaderBar.setValue(95);
			Database.NewAccount = new NewAccount("New Account", 300, 100, new ERL(Database.IMGNEWACCOUNT));
				new MouseHandler(Database.NewAccount, Constants.MENUSTATE_NEWACCOUNTMENU);
			loaderBar.setValue(100);			
			loaderBar.setString("Executing Eclipse");			
			loaderThread.setRunStatus(false);
			while(loaderThread.isAlive())
			;			
			ServerList.showForm();			
		}
		catch(Exception e)
		{
			eclipse.ErrorManager.handleError(e);
		}
	}	
}
